﻿using System;
using System.Windows.Forms;
using Freedom.Common.Collections;
using log4net;

namespace Freedom.WinCommon.Collections
{
    /// <summary>
    /// DictionaryCollection
    /// </summary>
    public abstract class DictionaryCollectionBase<T> : ObjectCollectionBase<T>, IDictionaryCollection, ILoadableObject
        where T : class
    {
        #region Properties


        /// <summary>
        /// ItemReadCount
        /// </summary>
        protected int ItemReadCount = 10;

        private readonly ObjectCollector<T> _loadedItems = new ObjectCollector<T>();
        private State _state = State.NotInitilized;

        private readonly ILog _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Gets a value indicating whether this instance is loaded.
        /// </summary>
        /// <value><c>true</c> if this instance is loaded; otherwise, <c>false</c>.</value>
        public bool IsLoaded
        {
            get { return _state == State.ReadyForUse; }
        }

        /// <summary>
        /// Current State
        /// </summary>
        public State CurrentState
        {
            get { return _state; }
        }

        /// <summary>
        /// Gets the state of the loading.
        /// </summary>
        /// <value>The get loaded items count.</value>
        /// <returns></returns>
        int? ILoadableObject.LoadedItemsCount
        {
            get { return IsLoaded ? null : _loadedItems.Count; }
        }
        #endregion



        /// <summary>
        /// Updates the state.
        /// </summary>
        public void UpdateState()
        {
            if (_state == State.Loaded)
                SetItems(_loadedItems.ExctractAll());
        }




        /// <summary>
        /// Loads the items.
        /// </summary>
        /// <param name="fromConstructor">if set to <c>true</c> [from constructor].</param>
        protected override void LoadItems(bool fromConstructor)
        {
            if (_state == State.Loading || _state == State.Loaded) return;


            ((MethodInvoker)DoLoading).BeginInvoke(null, null);
        }

        /// <summary>
        /// Called when [collection reset].
        /// </summary>
        protected override void OnCollectionReset()
        {
            _state = State.ReadyForUse;
            base.OnCollectionReset();
        }


        private void DoLoading()
        {
            try
            {
                var skip = 0;
                _state = State.Loading;

                T[] items;
                do
                {
                    items = ReadPage(skip, ItemReadCount);
                    if (items != null && items.Length > 0)
                    {
                        _loadedItems.Put(items);
                        skip += ItemReadCount;
                    }
                }
                while (items != null && items.Length == ItemReadCount);


            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
            finally
            {
                _state = State.Loaded;
            }
        }

        /// <summary>
        /// Reads the page.
        /// </summary>
        /// <param name="startIndex">The start index.</param>
        /// <param name="count">The count.</param>
        protected abstract T[] ReadPage(int startIndex, int count);

        
    }

    /// <summary>
    /// LoadingState
    /// </summary>
    public enum State
    {
        /// <summary>
        /// NotInitilized
        /// </summary>
        NotInitilized,
        /// <summary>
        /// Loading
        /// </summary>
        Loading,
        /// <summary>
        /// Loaded
        /// </summary>
        Loaded,
        /// <summary>
        /// ReadyForUse
        /// </summary>
        ReadyForUse
    }
}
